package cn.wgx.commons.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.List;

/**
 * 万能list转树型结构
 *
 * 利用反射获取id和pid
 */
@Slf4j
public class TreeUtil {

    /**
     * 入口, 默认children名字
     * @param list 需要变树的list
     * @param idField id的name
     * @param pidField pid的name
     * @param <E> 任何实体类型
     * @return jsonArray数组
     */
    public static <E> JSONArray getTreeArray(List<E> list, String idField, String pidField){
        return getTreeArray(list,0,idField,pidField,"children", null);
    }

    public static <E> JSONArray getTreeArray(List<E> list, Integer pid, String idField, String pidField){
        return getTreeArray(list,pid,idField,pidField,"children", null);
    }

    public static <E> JSONArray getTreeArray(List<E> list, String idField, String pidField, String childName){
        return getTreeArray(list,0,idField,pidField,childName, null);
    }

    public static <E> JSONArray getTreeArray(List<E> list, Integer _pid, String idName, String pidName, String childrenName, String titleName){
        JSONArray array = new JSONArray();
        for(E e:list){
            Object pid = getFiledObject(e, pidName);
            if(null == pid){
                break;
            }
            if(pid.equals((_pid!=null?_pid:0))){
                JSONObject jsonObject = (JSONObject) JSON.toJSON(e);
                if(null != titleName){
                    jsonObject.put("parent_"+titleName, "顶级");
                }
                array.add(findChildren(jsonObject, list, idName, pidName, childrenName, titleName));
            }
        }

        return array;
    }
    private static <E> JSONObject findChildren(JSONObject o, List<E> list, String idName, String pidName, String childrenName, String titleName) {
        for (E e : list) {
            Object id = o.get(idName);
            Object pid = getFiledObject(e, pidName);
            if ( id!= null && id.equals(pid)) {
                if (o.getJSONArray(childrenName) == null) {
                    o.put(childrenName, new JSONArray());
                }
                JSONObject child = (JSONObject)JSON.toJSON(e);
                if(null != titleName){
                    String string = o.getString(titleName);
                    if(null != string){
                        child.put("parent_"+titleName,string);
                    }
                }
                o.getJSONArray(childrenName).add(findChildren(child, list, idName, pidName, childrenName, titleName));
            }
        }
        return o;
    }

    private static <E> Object getFiledObject(E e, String fieldName){
        return getFiledObject(e, e.getClass(), fieldName);
    }

    private static <E> Object getFiledObject(E e, Class clazz, String fieldName){
        try {
            Field[] declaredFields = clazz.getDeclaredFields();
            for(Field field: declaredFields){
                if(fieldName.equals(field.getName())){
                    field.setAccessible(true);
                    return field.get(e);
                }
            }
            Class superclass = clazz.getSuperclass();
            if(!superclass.equals(Object.class)){
                return getFiledObject(e, superclass, fieldName);
            }
        } catch (Exception ex) {
            if(log.isDebugEnabled())
                ex.printStackTrace();
            log.error("转树失败-类名:{}.{}", e.getClass(), fieldName);
        }
        return null;
    }

}
